package com.haierp.service.impl;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.haierp.mapper.PurchaseStorageDetailMapper;
import com.haierp.model.purchase.PurchaseStorageDetail;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.druid.util.StringUtils;
import com.baomidou.framework.service.impl.SuperServiceImpl;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;
import com.haierp.enums.InoutOperatorType;
import com.haierp.enums.OrderStatus;
import com.haierp.enums.StockUpStatus;
import com.haierp.exception.ErpCommonException;
import com.haierp.exception.InventoryException;
import com.haierp.mapper.InventoryAreaMapper;
import com.haierp.mapper.InventoryMapper;
import com.haierp.model.ErpOrder;
import com.haierp.model.Inventory;
import com.haierp.model.InventoryArea;
import com.haierp.model.InventoryInout;
import com.haierp.model.InventoryRecord;
import com.haierp.model.InventoryRecord.InventoryType;
import com.haierp.model.InventoryRecord.OperatorType;
import com.haierp.service.IErpOrderService;
import com.haierp.service.IInventoryInoutService;
import com.haierp.service.IInventoryRecordService;
import com.haierp.service.IInventoryService;
import com.haierp.service.IWarehouseService;
import com.haierp.util.ErpOrderUtil;
import com.haierp.util.ShiroUtil;
import com.wangzhixuan.commons.shiro.ShiroUser;

@Service("inventoryService")
public class InventoryServiceImpl extends SuperServiceImpl<InventoryMapper, Inventory> implements IInventoryService {

	@Autowired
	private InventoryMapper inventoryMapper;
	@Autowired
	private InventoryAreaMapper inventoryAreaMapper;
	@Autowired
	private IInventoryRecordService inventoryRecordService;
	@Autowired
	private IErpOrderService erpOrderService;
	@Autowired
	IInventoryInoutService inventoryInoutService;
	@Autowired
	IWarehouseService warehouseService;
	@Autowired
	private PurchaseStorageDetailMapper purchaseStorageDetailMapper;
	

	/*@Override
	public int lockedInventoryOrder(Long outerOrderId) throws InventoryException {
		// List<OrderDetail> orderDetails = order.getOrderDetails();
		Map<String, Object> clumnMap = new HashMap<>();
		clumnMap.put("outer_order_id", outerOrderId);
		List<ErpOrder> erpOrders = erpOrderService.selectByMap(clumnMap);

		Map<Long, WarehouseCollector> warehouseCollectorMap = selectWarehousesByOrder(erpOrders);
		Set<Integer> stockStatuss = new HashSet<>();
		for (ErpOrder erpOrder : erpOrders) {
			// 分商品锁定库存， 仅仅扣减或锁定总库存 ，仓库库存不操作（仓库选择，仓库锁定 -> 异步？）
			int stockStatus = lockedInventroy(erpOrder, warehouseCollectorMap.get(erpOrder.getId()));
			stockStatuss.add(stockStatus);
		}
		if (stockStatuss.size() == 1) {
			return stockStatuss.iterator().next();
		} else {
			return WarehouseCollector.STOCKSTATUS_PART_READY;
		}
	}*/

	@Override
	@Deprecated
	public int lockedInventroyErpOrder(ErpOrder erpOrder) throws InventoryException {
		WarehouseCollector warehouseCollector = selectWarehousesByOrderDetail(erpOrder);
		lockedInventroy(erpOrder, warehouseCollector);
		return warehouseCollector.getStockStatus();
	}

	@Override
	@Deprecated
	public int lockedInventroy(ErpOrder erpOrder, WarehouseCollector warehouseCollector) throws InventoryException {
		int bookedSum = warehouseCollector.getBooked() + warehouseCollector.getTransBooked();
		if (bookedSum == 0) {
			return warehouseCollector.getStockStatus();
		}

		Long itemId = erpOrder.getItemId();
		Long skuId = erpOrder.getSkuId();
		// 悲观锁 锁定库存记录，防止并发
		Inventory inventory = inventoryMapper.getInventoryBySkuId(itemId, skuId);

		// 为空说明本次不用锁定
		if ((warehouseCollector.getBooked()+warehouseCollector.getTransBooked())==0) {
			return warehouseCollector.getStockStatus();
		} else {// 需要锁定

			int availableInv = inventory.getAvailableInv();// 可售库存
			int availableTransInv = inventory.getAvailableTransInv();// 可用在途库存
			int inventoryBooked = warehouseCollector.getBooked();// 实际库存锁定量
			int transBooked = warehouseCollector.getTransBooked();// 在途库存锁定量

			int records = inventoryMapper.updateLockInventory(inventory.getId(), inventoryBooked, transBooked);
			if (records == 0) {
				throw new InventoryException(String.format(
						"data expiration exception : detailId[%d],StockStatus[%d],CalcInventory[%d],ActualInventory[%d],CalcTransInventory[%d],ActualTransInventory[%d]",
						erpOrder.getId(), warehouseCollector.getStockStatus(), inventoryBooked, availableInv,
						transBooked, availableTransInv));
			}

			// 记录实际锁定记录
			insertInventoryLockedRecord(erpOrder, warehouseCollector, availableInv);
			// 记录在途库存锁定记录
			insertTransInventoryLockedRecord(erpOrder, warehouseCollector, availableTransInv);

			// 如果是备货完成，检查一下
			if (warehouseCollector.getStockStatus() == WarehouseCollector.STOCKSTATUS_FINISHED) {
				int alreadyBooked = inventoryRecordService.sumBookedBySkuId(erpOrder.getOuterOrderId(),
						erpOrder.getId());
				if (erpOrder.getQuantity() != alreadyBooked) {
					throw new InventoryException(String.format(
							"inventory stockstatus check exception : detailId[%d],Booked[%d],Quantity[%d]",
							erpOrder.getId(), warehouseCollector.getStockStatus(), alreadyBooked,
							erpOrder.getQuantity()));
				}
			}

			return warehouseCollector.getBooked();
		}
	}

	/**
	 * 一个货架入仓到另外一个货架
	 * 
	 * @param inventoryAreaId
	 * @param toTrans
	 * @param otherInventoryAreaId
	 */
	@Override
	public void transToOtherInventory(InventoryArea inventoryArea, int toTrans, String positionNo, String onlineNumber) throws InventoryException{
		
		if (inventoryArea.getTransInv() < toTrans) {
			throw new InventoryException(String.format("InventoryArea[%d] transInv less than toTrans[%d]",
					inventoryArea.getTransInv(), toTrans));
		}
		int availableInv = inventoryArea.getTransInv() - inventoryArea.getLockedTransInv();
		// 1、如果可用的在途库存不够，则先释放，直到够用为止
		if (availableInv < toTrans) {
			int lockedCheckInv = toTrans - availableInv;// 需要释放锁定库存
			// int release = 0;
			List<InventoryRecord> records = inventoryRecordService.sumInventoryCheckRecord(inventoryArea.getId(),
					InventoryType.TRANS_INV, Arrays.asList(OrderStatus.INIT.getCode()/*, OrderStatus.CONFIRM.getCode()*/));
			for (InventoryRecord inventoryRecord : records) {
				int sumBooked = inventoryRecord.getBooked();
				lockedCheckInv -= sumBooked;
				// release += sumBooked;
				ErpOrder erpOrder = erpOrderService.selectById(inventoryRecord.getErpOrderId());
				releaseInventory(erpOrder);
				if (lockedCheckInv <= 0) {
					break;
				}
			}
			if (lockedCheckInv > 0) {
				throw new InventoryException("inventoryCheck is not enough!");
			}
			inventoryArea = inventoryAreaMapper.selectById(inventoryArea.getId());
		}
		
		
		// 2、总库存操作： 减掉在途库存 转移到 实际库存
		Inventory inventory = inventoryMapper.getInventoryBySkuId(inventoryArea.getItemId(), inventoryArea.getSkuId());
		int inventoryRecords = inventoryMapper.updateInventoryTransCheck(inventory.getId(), inventory.getTransInv(),
				toTrans);
		if (inventoryRecords <= 0) {
			throw new InventoryException("Inventory data expire exception!");
		}

		// 3、减掉原货架上的在途库存
		int inventoryAreaRecords = inventoryAreaMapper.updateInventoryAreaTransCheck(inventoryArea.getId(),
				inventoryArea.getTransInv(), toTrans);
		if (inventoryAreaRecords <= 0) {
			throw new InventoryException("inventoryArea data expire exception!");
		}
		
		//4、转移到新的货架的实际库存上
		InventoryArea otherInventoryArea = inventoryAreaMapper.getInventoryArea(inventoryArea.getItemId(), inventoryArea.getSkuId(), inventoryArea.getWarehouseId(), positionNo);
		if(otherInventoryArea==null) {
			otherInventoryArea = new InventoryArea();
			otherInventoryArea.setCompanyId(inventoryArea.getCompanyId());//转移到新的货架号 新增companyId
			otherInventoryArea.setItemId(inventoryArea.getItemId());
			otherInventoryArea.setSkuId(inventoryArea.getSkuId());
			otherInventoryArea.setItemName(inventoryArea.getItemName());
			otherInventoryArea.setUpc(inventoryArea.getUpc());
			otherInventoryArea.setColor(inventoryArea.getColor());
			otherInventoryArea.setScale(inventoryArea.getScale());
			otherInventoryArea.setSkuCode(inventoryArea.getSkuCode());
			otherInventoryArea.setSkuPic(inventoryArea.getSkuPic());
			otherInventoryArea.setInventory(toTrans);
			otherInventoryArea.setLockedInv(0);
			otherInventoryArea.setTransInv(0);
			otherInventoryArea.setLockedTransInv(0);
			otherInventoryArea.setWarehouseId(inventoryArea.getWarehouseId());
			otherInventoryArea.setWarehouseName(inventoryArea.getWarehouseName());
			otherInventoryArea.setPositionNo(positionNo);
			otherInventoryArea.setGmtCreate(new Date());
			otherInventoryArea.setGmtModify(new Date());
			inventoryAreaMapper.insert(otherInventoryArea);
		} else {
			int otherInventoryAreaRecords = inventoryAreaMapper.updateInventoryAreaAddInventory(otherInventoryArea.getId(),
					otherInventoryArea.getInventory(), toTrans);
			if (otherInventoryAreaRecords <= 0) {
				throw new InventoryException("otherInventoryAreaRecords data expire exception!");
			}
		}
		
		//记录库存变动日志 。FIXME ：仅仅记录了到新货架的日志，未记录来自于哪个货架
		String userCreate = null;
		try {
			ShiroUser su = ShiroUtil.getShiroUser();
			userCreate = su.getLoginName();
		} catch (Exception e) {
			throw new ErpCommonException("没有登入");
		}
		InventoryInout inventoryInout = new InventoryInout();
		inventoryInout.setCompanyId(otherInventoryArea.getCompanyId());
		inventoryInout.setItemId(otherInventoryArea.getItemId());
		inventoryInout.setSkuCode(otherInventoryArea.getSkuCode());
		inventoryInout.setSkuId(otherInventoryArea.getSkuId());
		inventoryInout.setQuantity(toTrans);
		inventoryInout.setSkuCode(otherInventoryArea.getSkuCode());
		inventoryInout.setInventoryAreaId(otherInventoryArea.getId());
		inventoryInout.setOriginInventoryAreaId(inventoryArea.getId());
		inventoryInout.setWarehouseId(otherInventoryArea.getWarehouseId());
		inventoryInout.setPositionNo(otherInventoryArea.getPositionNo());
		inventoryInout.setOnlineNumber(onlineNumber);
		inventoryInout.setOperatorType(InoutOperatorType.TRANS_IN.getCode());
		inventoryInout.setUserCreate(userCreate);
		inventoryInout.setGmtCreate(new Date());
		inventoryInout.setGmtModify(new Date());
		inventoryInoutService.insert(inventoryInout);
	}
	
	@Override
	public void transToInventory(Long inventoryAreaId, int toTrans, String positionNo, Long storageDetailId) throws InventoryException {
		String onlineNumber = null;
		if (storageDetailId != null) {
			PurchaseStorageDetail one = purchaseStorageDetailMapper.selectById(storageDetailId);
			one.setOnlineQuantity(one.getOnlineQuantity() - toTrans);
			one.setInventoryAreaId(inventoryAreaId);
			purchaseStorageDetailMapper.updateSelectiveById(one);

			onlineNumber = one.getOnlineNumber();
		}

		InventoryArea inventoryArea = inventoryAreaMapper.selectById(inventoryAreaId);
		if (inventoryArea == null) {
			throw new InventoryException(
					String.format("transToInventory exception :   InventoryArea[%d] is not exist!", inventoryAreaId));
		}
		if(StringUtils.isEmpty(positionNo)||positionNo.equals(inventoryArea.getPositionNo())){
			transToSameInventory(inventoryArea, toTrans, onlineNumber);
		}else{
			transToOtherInventory(inventoryArea, toTrans, positionNo, onlineNumber);
		}
	}

	@Override
	public void transToSameInventory(InventoryArea inventoryArea, int toTrans, String onlineNumber) throws InventoryException {
		int lockedTransInv = inventoryArea.getLockedTransInv();// 已锁定的在途数量
		int transInv = inventoryArea.getTransInv();// 在途数量

		if (transInv < toTrans) {
			throw new InventoryException(
					String.format("transToInventory exception :   InventoryArea[%d ，%d] is less than toTrans[%d]!",
							inventoryArea.getId(), transInv, toTrans));
		}
		int lockedTransToInv = Math.min(toTrans, lockedTransInv);// 在途锁定 ->
																	// 实际库存锁定的数量
		int records = inventoryAreaMapper.updateTransToInventoryArea(inventoryArea.getId(), toTrans, lockedTransToInv,
				lockedTransInv);
		if (records == 0) {// 数据过期，直接抛异常
			throw new InventoryException(
					String.format("transToInventory data expiration exception :InventoryArea[%d] , toTrans[%d] ",
							inventoryArea.getId(), toTrans));
		}
		Inventory inventory = inventoryMapper.getInventoryBySkuId(inventoryArea.getItemId(), inventoryArea.getSkuId());
		// 修改inventory表
		int iRecords = inventoryMapper.updateTransToInventory(inventoryArea.getItemId(), inventoryArea.getSkuId(),
				toTrans, lockedTransToInv, inventory.getLockedTransInv());
		if (iRecords == 0) {// 数据过期，直接抛异常
			throw new InventoryException(String.format(
					"transToInventory updateTransToInventory data expiration exception :Inventory[%d] , toTrans[%d] ",
					inventory.getId(), toTrans));
		}

		// 记录入仓日志
		String userCreate = null;
		try {
			ShiroUser su = ShiroUtil.getShiroUser();
			userCreate = su.getLoginName();
		} catch (Exception e) {
			throw new ErpCommonException("没有登入");
		}
		InventoryInout inventoryInout = new InventoryInout();
		inventoryInout.setItemId(inventoryArea.getItemId());
		inventoryInout.setCompanyId(inventoryArea.getCompanyId());
		inventoryInout.setSkuCode(inventoryArea.getSkuCode());
		inventoryInout.setSkuId(inventoryArea.getSkuId());
		inventoryInout.setQuantity(toTrans);
		inventoryInout.setSkuCode(inventoryArea.getSkuCode());
		inventoryInout.setInventoryAreaId(inventoryArea.getId());
		inventoryInout.setOriginInventoryAreaId(inventoryArea.getId());
		inventoryInout.setWarehouseId(inventoryArea.getWarehouseId());
		inventoryInout.setPositionNo(inventoryArea.getPositionNo());
		inventoryInout.setOnlineNumber(onlineNumber);
		inventoryInout.setOperatorType(InoutOperatorType.TRANS_IN.getCode());
		inventoryInout.setUserCreate(userCreate);
		inventoryInout.setGmtCreate(new Date());
		inventoryInout.setGmtModify(new Date());
		inventoryInoutService.insert(inventoryInout);

		if (lockedTransToInv > 0) {
			// 上面更新成功，变更inventoryRecord表中的在途转实际
			Map<String, Object> param = new HashMap<>();
			param.put("inventory_area_id", inventoryArea.getId());
			param.put("inventory_type", InventoryType.TRANS_INV);
			List<InventoryRecord> inventoryRecords = inventoryRecordService.selectByMap(param);// 需要在途转实际的记录
			int remainToTrans = lockedTransToInv;
			// 用于存储变更过类型的订单列表，这些订单需要重新计算stockup的状态， 例如是在途备货完成的，可能需要改成备货完成
			Set<Long> orderIds = new HashSet<>();

			for (InventoryRecord inventoryRecord : inventoryRecords) {
				int trans = inventoryRecord.getBooked();
				if (remainToTrans >= trans) {// 直接把类型转变为实际库存锁定类型
					inventoryRecord.setInventoryType(InventoryType.INVENTORY);
					inventoryRecordService.updateSelectiveById(inventoryRecord);
					orderIds.add(inventoryRecord.getErpOrderId());
					remainToTrans -= trans;
					if (remainToTrans == 0) {
						break;
					}
				} else {// 如果剩下的数量不够一条record的数量，则需要拆分record,例如转换5个，而recordbooked
						// =10: [TRANS_INV,10] -> [TRANS_INV,5]+ [INVENTORY,5]
					inventoryRecord.setBooked(trans - remainToTrans);
					inventoryRecordService.updateSelectiveById(inventoryRecord);

					// 剩下的新增一条InventoryType.INVENTORY的记录
					ErpOrder erpOrder = erpOrderService.selectById(inventoryRecord.getErpOrderId());
					inventoryRecordService.insert(buildLockedRecord(erpOrder, remainToTrans, inventoryArea,
							inventoryRecord.getSkuId(), InventoryType.INVENTORY));

					orderIds.add(inventoryRecord.getErpOrderId());
					remainToTrans = 0;
					break;
				}
			}

			if (remainToTrans > 0) {// 数据有问题
				throw new InventoryException(String.format("transToInventory exception :  remainToTrans > 0 !"));
			}

			// //重新计算备货状态
			for (Long orderId : orderIds) {
				ErpOrder erpOrder = erpOrderService.selectById(orderId);

				Integer stockStatus = erpOrder.getStockStatus();

				List<InventoryRecord> inventoryTypeBooked = inventoryRecordService
						.sumBookedByInventoryType(erpOrder.getOuterOrderId(), orderId);
				int quantity = erpOrder.getQuantity();// 订单购买量
				int sumBooked = inventoryTypeBooked.stream().mapToInt((t) -> t.getBooked()).sum();// 已经预定的总量

				int decideStockup = decideStockup(inventoryTypeBooked);

				if (quantity == sumBooked) {// 全部预定,重新订单计算stockstatus
					if (decideStockup == 2) {// 备货完成
						stockStatus = WarehouseCollector.STOCKSTATUS_FINISHED;
					} else if (decideStockup == 1) {// 混合备货完成
						stockStatus = WarehouseCollector.STOCKSTATUS_MIX_STOCKUP;
					} else {
						new InventoryException(String.format(
								"transToInventory  calc order[%d] stockStatus exception : decideStockup[%d]", orderId,
								decideStockup));
					}
					erpOrder.setStockStatus(stockStatus);
					erpOrderService.updateSelectiveById(erpOrder);
				}
			}
		}
	}

	/**
	 * 订单发货
	 */
	@Override
	public void sendInventroyOrder(ErpOrder order) throws InventoryException {

		Inventory inventory = inventoryMapper.getInventoryBySkuId(order.getItemId(), order.getSkuId());

		List<InventoryRecord> records = inventoryRecordService.queryByErpOrderId(order.getId());
		int sumSend = 0;
		for (InventoryRecord inventoryRecord : records) {
			InventoryArea inventoryArea = inventoryAreaMapper.selectById(inventoryRecord.getInventoryAreaId());
			if (inventoryArea == null) {
				throw new InventoryException(
						String.format("sendInventroy exception : InventoryRecord[%d]  InventoryAreaId[%d] is null",
								inventoryRecord.getId(), inventoryRecord.getInventoryAreaId()));
			}
			int send = inventoryRecord.getBooked();
			inventoryArea.setLockedInv(inventoryArea.getLockedInv() - send);
			inventoryArea.setInventory(inventoryArea.getInventory() - send);

			if (inventoryArea.getLockedInv() < 0 || inventoryArea.getInventory() < 0) {
				throw new InventoryException(String.format(
						"sendInventroy exception : InventoryRecord[%d] remainLocked[%d] or remainInventory[%d] error!",
						inventoryRecord.getId(), inventoryArea.getLockedInv(), inventoryArea.getInventory()));
			}
			sumSend += send;
			inventoryAreaMapper.updateSelectiveById(inventoryArea);

			// 记录出仓日志
			String userCreate = null;
			Long companyId = null;
			try {
				ShiroUser su = ShiroUtil.getShiroUser();
				userCreate = su.getLoginName();
				companyId = su.getCompanyId();
			} catch (Exception e) {
				throw new ErpCommonException("没有登入");
			}
			InventoryInout inventoryInout = new InventoryInout();
			inventoryInout.setCompanyId(companyId);//所属公司
			inventoryInout.setItemId(inventoryRecord.getItemId());
			inventoryInout.setSkuCode(inventoryRecord.getSkuCode());
			inventoryInout.setSkuId(inventoryRecord.getSkuId());
			inventoryInout.setItemId(inventoryRecord.getItemId());
			inventoryInout.setQuantity(inventoryRecord.getBooked());
			inventoryInout.setInventoryAreaId(inventoryRecord.getInventoryAreaId());
			inventoryInout.setWarehouseId(inventoryRecord.getWarehouseId());
			inventoryInout.setPositionNo(inventoryRecord.getPositionNo());
			inventoryInout.setErpOrderId(order.getId());
			inventoryInout.setOperatorType(InoutOperatorType.SALE_OUT.getCode());
			inventoryInout.setUserCreate(userCreate);
			inventoryInout.setGmtCreate(new Date());
			inventoryInout.setGmtModify(new Date());
			inventoryInoutService.insert(inventoryInout);
		}
		// 总库存的锁定和库存减掉
		inventory.setLockedInv(inventory.getLockedInv() - sumSend);
		inventory.setInventory(inventory.getInventory() - sumSend);
		inventory.setGmtModify(new Date());
		inventoryMapper.updateSelectiveById(inventory);
		if (sumSend != order.getQuantity()) {
			throw new InventoryException(String.format(
					"sendInventroy exception : sumSend[%d] not equals orderDetail[id =%d, quantity = %d]  !", sumSend,
					order.getId(), order.getQuantity()));
		}

	}

	@Override
	public int releaseInventory(ErpOrder order) throws InventoryException {
		// 悲观锁 锁定库存记录，防止并发
		Inventory inventory = inventoryMapper.getInventoryBySkuId(order.getItemId(), order.getSkuId());

		List<InventoryRecord> records = inventoryRecordService.queryByErpOrderId(order.getId());
		int sumInvRelease = 0;
		int sumTransRelease = 0;
		for (InventoryRecord inventoryRecord : records) {
			InventoryArea inventoryArea = inventoryAreaMapper.selectById(inventoryRecord.getInventoryAreaId());
			if (inventoryArea == null) {
				throw new InventoryException(
						String.format("sendInventroy exception : InventoryRecord[%d]  InventoryAreaId[%d] is null",
								inventoryRecord.getId(), inventoryRecord.getInventoryAreaId()));
			}
			int release = inventoryRecord.getBooked();

			if (InventoryType.INVENTORY == inventoryRecord.getInventoryType()) {
				inventoryArea.setLockedInv(inventoryArea.getLockedInv() - release);
				if (inventoryArea.getLockedInv() < 0) {
					throw new InventoryException(String.format(
							"sendInventroy exception : InventoryRecord[%d] remainLocked[%d] or remainInventory[%d] error!",
							inventoryRecord.getId(), inventoryArea.getLockedInv(), inventoryArea.getInventory()));
				}
				sumInvRelease += release;
			} else {
				inventoryArea.setLockedTransInv(inventoryArea.getLockedTransInv() - release);
				if (inventoryArea.getLockedInv() < 0) {
					throw new InventoryException(String.format(
							"sendInventroy exception : InventoryRecord[%d] remainLocked[%d] or remainInventory[%d] error!",
							inventoryRecord.getId(), inventoryArea.getLockedInv(), inventoryArea.getInventory()));
				}
				sumTransRelease += release;
			}

			inventoryAreaMapper.updateSelectiveById(inventoryArea);
			// 删除预定记录
			inventoryRecordService.deleteById(inventoryRecord.getId());
		}
		// 总库存的锁定和库存减掉
		inventory.setLockedInv(inventory.getLockedInv() - sumInvRelease);
		inventory.setLockedTransInv(inventory.getLockedTransInv() - sumTransRelease);
		inventory.setGmtModify(new Date());
		inventoryMapper.updateSelectiveById(inventory);

		// 修改订单状态 为已释放
		order.setStockStatus(StockUpStatus.RELEASED.getCode());
		order.setWarehouseId(null);
		order.setGmtModify(new Date());
		erpOrderService.updateById(order);

		return sumTransRelease + sumInvRelease;
	}

	@Override
	public void inventoryCheckOut(Long inventoryAreaId, int quantity, String inoutReason) throws InventoryException {
		InventoryArea inventoryArea = inventoryAreaMapper.selectById(inventoryAreaId);
		if (inventoryArea == null) {
			throw new InventoryException(String.format("Inventory[id:%d] is not exist!", inventoryAreaId));
		}
		if (inventoryArea.getInventory() < quantity) {
			throw new InventoryException(String.format("InventoryArea[%d] inventory less than check quantity[%d]",
					inventoryArea.getInventory(), quantity));
		}
		int availableInv = inventoryArea.getInventory() - inventoryArea.getLockedInv();
		if (availableInv < quantity) {
			int lockedCheckInv = quantity - availableInv;// 需要释放锁定库存
			// int release = 0;
			List<InventoryRecord> records = inventoryRecordService.sumInventoryCheckRecord(inventoryAreaId,
					InventoryType.INVENTORY, Arrays.asList(OrderStatus.INIT.getCode()/*, OrderStatus.CONFIRM.getCode()*/));
			for (InventoryRecord inventoryRecord : records) {
				int sumBooked = inventoryRecord.getBooked();
				lockedCheckInv -= sumBooked;
				// release += sumBooked;
				ErpOrder erpOrder = erpOrderService.selectById(inventoryRecord.getErpOrderId());
				releaseInventory(erpOrder);
				if (lockedCheckInv <= 0) {
					break;
				}
			}
			if (lockedCheckInv > 0) {
				throw new InventoryException("inventoryCheck is not enough!");
			}
			inventoryArea = inventoryAreaMapper.selectById(inventoryAreaId);
		}
		// 1、减掉总库存
		Inventory inventory = inventoryMapper.getInventoryBySkuId(inventoryArea.getItemId(), inventoryArea.getSkuId());
		int inventoryRecords = inventoryMapper.updateInventoryCheck(inventory.getId(), inventory.getInventory(),
				quantity);
		if (inventoryRecords <= 0) {
			throw new InventoryException("Inventory data expire exception!");
		}

		// 2、盘点减掉货架库存
		int inventoryAreaRecords = inventoryAreaMapper.updateInventoryAreaCheck(inventoryArea.getId(),
				inventoryArea.getInventory(), quantity);
		if (inventoryAreaRecords <= 0) {
			throw new InventoryException("inventoryArea data expire exception!");
		}

		// 记录盘点日志
		String userCreate = null;
		try {
			ShiroUser su = ShiroUtil.getShiroUser();
			userCreate = su.getLoginName();
		} catch (Exception e) {
			throw new ErpCommonException("没有登入");
		}
		InventoryInout inventoryInout = new InventoryInout();
		inventoryInout.setItemId(inventory.getItemId());
		inventoryInout.setCompanyId(inventory.getCompanyId());//出入库记录所属公司
		inventoryInout.setSkuCode(inventory.getSkuCode());
		inventoryInout.setSkuId(inventory.getSkuId());
		inventoryInout.setItemId(inventory.getItemId());
		inventoryInout.setQuantity(quantity);
		inventoryInout.setInventoryAreaId(inventoryArea.getId());
		inventoryInout.setWarehouseId(inventoryArea.getWarehouseId());
		inventoryInout.setPositionNo(inventoryArea.getPositionNo());
		inventoryInout.setOperatorType(InoutOperatorType.CHECK_OUT.getCode());
		inventoryInout.setUserCreate(userCreate);
		inventoryInout.setInoutReason(inoutReason);
		inventoryInout.setGmtCreate(new Date());
		inventoryInout.setGmtModify(new Date());
		inventoryInoutService.insert(inventoryInout);
	}

	@Override
	public Inventory queryInventoryBySkuId(Long itemId, Long skuId) {
		return inventoryMapper.getInventoryBySkuId(itemId, skuId);
	}

	/*private Map<Long, WarehouseCollector> selectWarehousesByOrder(List<ErpOrder> erpOrders) throws InventoryException {
		Map<Long, WarehouseCollector> warehouseCollectorMap = new HashMap<>();
		for (ErpOrder erpOrder : erpOrders) {
			warehouseCollectorMap.put(erpOrder.getId(), selectWarehousesByOrderDetail(erpOrder));
		}
		return warehouseCollectorMap;
	}*/

	private int sumBooked(List<InventoryRecord> inventoryRecords) {
		int sumBooked = 0;
		if (inventoryRecords == null || inventoryRecords.isEmpty()) {
			return sumBooked;
		}
		for (InventoryRecord inventoryRecord : inventoryRecords) {
			sumBooked += inventoryRecord.getBooked();
		}
		return sumBooked;
	}

	private int decideStockup(List<InventoryRecord> inventoryRecords) throws InventoryException {
		if (inventoryRecords == null || inventoryRecords.size() == 0) {
			return 0;// 无记录
		} else if (inventoryRecords.size() == 2) {
			return 1;// 混合
		} else if (inventoryRecords.size() == 1) {
			InventoryRecord inventoryRecord = inventoryRecords.get(0);
			if (InventoryType.INVENTORY == inventoryRecord.getInventoryType()) {
				return 2;
			} else if (InventoryType.TRANS_INV == inventoryRecord.getInventoryType()) {
				return 3;
			}
		}
		throw new InventoryException("decideStockup incorrect exception !");

	}
	@Deprecated
	private WarehouseCollector selectWarehousesByOrderDetail(ErpOrder erpOrder) throws InventoryException {
		WarehouseCollector warehouseColl = new WarehouseCollector();
		warehouseColl.setErpOrderId(erpOrder.getId());
		warehouseColl.setOrderId(erpOrder.getOuterOrderId());

		// 从预定记录里面查询已经预定的量
		List<InventoryRecord> inventoryRecords = inventoryRecordService
				.sumBookedByInventoryType(erpOrder.getOuterOrderId(), erpOrder.getId());

		int booked = sumBooked(inventoryRecords);

		int decideStockup = decideStockup(inventoryRecords);
		// 订单购买量
		int quantity = erpOrder.getQuantity();
		// 已预定量等于购买量，说明已经锁定完成,直接返回
		if (booked == quantity) {
			//
			if (decideStockup == 2) {
				warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_FINISHED);// 备货完成
			} else if (decideStockup == 3) {
				warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_TRANS_STOCKUP);// 全部在途备货
			} else if (decideStockup == 1) {
				warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_MIX_STOCKUP);// 混合备货完成
			} else {
				throw new InventoryException("stockstatus incorrect !");
			}
			return warehouseColl;
		}

		// 剩余预定量
		int remainQuantity = quantity - booked;
		if (remainQuantity < 0) {
			throw new InventoryException(String.format("error : ErpOrder[id:%d,quantity:%d]  < already Booked[%d] !",
					erpOrder.getId(), quantity, booked));
		}

		// 查询各仓库总库存
		List<InventoryArea> sumInventorys = inventoryAreaMapper.sumInventoryBySkuIdGroupbyWarehouse(erpOrder.getItemId(),
				erpOrder.getSkuId(),null);

		// 如果没有足够的单个仓库，则从多仓库查找，暂时不区分算法，找出最先足够的多个仓库
		Map<Long, Integer> inventoryAreaMap = new LinkedHashMap<>();// 记录实际库存预定量
		// int calcQuantity = quantity;
		// int totalBooked = 0;// 可预定总量
		int inventoryBooked = 0;
		// 1、先循环预定所有实际仓库库存
		for (InventoryArea sumInventory : sumInventorys) {
			int availableBooked = sumInventory.getAvailableInv();
			if (availableBooked == 0) {
				continue;
			}
			if (remainQuantity >= availableBooked) {
				inventoryAreaMap.put(sumInventory.getWarehouseId(), availableBooked);

				inventoryBooked += availableBooked;// 此仓库可预定量
				remainQuantity -= availableBooked;
				if (remainQuantity == 0) {
					break;
				}
			} else {
				inventoryAreaMap.put(sumInventory.getWarehouseId(), remainQuantity);
				inventoryBooked += remainQuantity;
				remainQuantity = 0;
				break;
			}
		}

		int transInvBooked = 0;
		Map<Long, Integer> inventoryAreaTransMap = new LinkedHashMap<>();
		// 2、循环检查在途数量
		if (remainQuantity > 0) {
			for (InventoryArea sumInventory : sumInventorys) {
				int availableTransInv = sumInventory.getAvailableTransInv();
				if (availableTransInv == 0) {
					continue;
				}
				if (remainQuantity >= availableTransInv) {
					inventoryAreaTransMap.put(sumInventory.getWarehouseId(), availableTransInv);
					transInvBooked += availableTransInv;// 此仓库可预定量
					remainQuantity -= availableTransInv;
					if (remainQuantity == 0) {
						break;
					}
				} else {
					inventoryAreaTransMap.put(sumInventory.getWarehouseId(), remainQuantity);
					transInvBooked += remainQuantity;
					remainQuantity = 0;
					break;
				}
			}
		}

		if (booked == 0 && inventoryAreaMap.isEmpty() && inventoryAreaTransMap.isEmpty()) {
			warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_NOT_READY);// 未备货
		} else if (remainQuantity == 0) {// 备货完成
			if (decideStockup == 1) {
				warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_MIX_STOCKUP);// 混合备货完成
				warehouseColl.setBooked(inventoryBooked);
				warehouseColl.setTransBooked(transInvBooked);
			} else if (decideStockup == 2) {
				if (inventoryAreaTransMap.isEmpty()) {
					warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_FINISHED);// 备货完成
					warehouseColl.setBooked(inventoryBooked);
					warehouseColl.setTransBooked(transInvBooked);
				} else {
					warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_MIX_STOCKUP);// 混合备货完成
					warehouseColl.setBooked(inventoryBooked);
					warehouseColl.setTransBooked(transInvBooked);
				}

			} else if (decideStockup == 3) {
				if (inventoryAreaMap.isEmpty()) {
					warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_TRANS_STOCKUP);// 全部在途备货完成
					warehouseColl.setBooked(inventoryBooked);
					warehouseColl.setTransBooked(transInvBooked);
				} else {
					warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_MIX_STOCKUP);// 混合备货完成
					warehouseColl.setBooked(inventoryBooked);
					warehouseColl.setTransBooked(transInvBooked);
				}
			} else if (decideStockup == 0) {
				if (!inventoryAreaMap.isEmpty() && !inventoryAreaTransMap.isEmpty()) {
					warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_MIX_STOCKUP);// 混合备货完成
					warehouseColl.setBooked(inventoryBooked);
					warehouseColl.setTransBooked(transInvBooked);
				} else if (!inventoryAreaMap.isEmpty()) {
					warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_FINISHED);// 备货完成
					warehouseColl.setBooked(inventoryBooked);
					warehouseColl.setTransBooked(transInvBooked);
				} else if (!inventoryAreaTransMap.isEmpty()) {
					warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_TRANS_STOCKUP);// 全部在途备货完成
					warehouseColl.setBooked(inventoryBooked);
					warehouseColl.setTransBooked(transInvBooked);
				} else {
					throw new InventoryException("remainQuantity decideStockup incorrect !");
				}
			}
		} else {
			warehouseColl.setStockStatus(WarehouseCollector.STOCKSTATUS_PART_READY);// 部分备货
			warehouseColl.setBooked(inventoryBooked);
			warehouseColl.setTransBooked(transInvBooked);
		}

		return warehouseColl;
		// }
	}

	public static class WarehouseCollector {

		public static final int STOCKSTATUS_NOT_READY = StockUpStatus.INIT.getCode();// 未备货
		public static final int STOCKSTATUS_PART_READY = StockUpStatus.PART.getCode();// 部分备货
		public static final int STOCKSTATUS_FINISHED = StockUpStatus.STOCKUP.getCode();// 备货完成
		public static final int STOCKSTATUS_TRANS_STOCKUP = StockUpStatus.TRANS_STOCKUP.getCode();// 全部在途备货
		public static final int STOCKSTATUS_TRANS_PART = StockUpStatus.TRANS_PART.getCode();// 部分在途备货
		public static final int STOCKSTATUS_MIX_STOCKUP = StockUpStatus.MIX_STOCKUP.getCode();// 混合备货完成

		private Long orderId;
		private Long erpOrderId;
		private Integer stockStatus;// 备货状态 0:未备货 1:部分备货 2 备货完成
		private int booked;// 本次预定量
		private int transBooked;// 本次在途预定量
		private int lastBooked; //上次预定在途（数据库）
		private int lastTransBooked; //上次预定在途（数据库）
		private Long warehouseId;//仓库ID
		private int quantity;//erporder 购买数量
		private ErpOrder erpOrder;
//		private Map<Long, Integer> warehouseMap;// 实际
//		private Map<Long, Integer> transWarehouseMap;// 在途

		public Integer getStockStatus() {
			return stockStatus;
		}

		public void setStockStatus(Integer stockStatus) {
			this.stockStatus = stockStatus;
		}

		
//		public Map<Long, Integer> getWarehouseMap() {
//			return warehouseMap;
//		}
//
//		public void setWarehouseMap(Map<Long, Integer> warehouseMap) {
//			this.warehouseMap = warehouseMap;
//		}

		public int getQuantity() {
			return quantity;
		}

		public void setQuantity(int quantity) {
			this.quantity = quantity;
		}

		public Long getWarehouseId() {
			return warehouseId;
		}

		public void setWarehouseId(Long warehouseId) {
			this.warehouseId = warehouseId;
		}

		public Long getOrderId() {
			return orderId;
		}

		public void setOrderId(Long orderId) {
			this.orderId = orderId;
		}

	
		public Long getErpOrderId() {
			return erpOrderId;
		}

		public void setErpOrderId(Long erpOrderId) {
			this.erpOrderId = erpOrderId;
		}

		public int getBooked() {
			return booked;
		}

		public void setBooked(int booked) {
			this.booked = booked;
		}

//		public Map<Long, Integer> getTransWarehouseMap() {
//			return transWarehouseMap;
//		}
//
//		public void setTransWarehouseMap(Map<Long, Integer> transWarehouseMap) {
//			this.transWarehouseMap = transWarehouseMap;
//		}

		public int getTransBooked() {
			return transBooked;
		}

		public void setTransBooked(int transBooked) {
			this.transBooked = transBooked;
		}

		public ErpOrder getErpOrder() {
			return erpOrder;
		}

		public void setErpOrder(ErpOrder erpOrder) {
			this.erpOrder = erpOrder;
		}

		public int getLastBooked() {
			return lastBooked;
		}

		public void setLastBooked(int lastBooked) {
			this.lastBooked = lastBooked;
		}

		public int getLastTransBooked() {
			return lastTransBooked;
		}

		public void setLastTransBooked(int lastTransBooked) {
			this.lastTransBooked = lastTransBooked;
		}

	}

	private void insertInventoryLockedRecord(ErpOrder erpOrder, WarehouseCollector warehouseCollector, int availableInv)
			throws InventoryException {
		Long itemId = erpOrder.getItemId();
		Long skuId = erpOrder.getSkuId();
		Long warehouseId = warehouseCollector.getWarehouseId();
		int booked = warehouseCollector.getBooked();
		List<InventoryArea> areas = inventoryAreaMapper.queryInventoryAreaByWarehouse(warehouseId, itemId, skuId);
		for (InventoryArea inventoryArea : areas) {
			int available = inventoryArea.getAvailableInv();
			if (available == 0) {
				continue;
			}
			int bookedArea = 0;
			if (booked >= available) {
				bookedArea = available;
				booked -= available;
			} else {
				bookedArea = booked;
				booked = 0;
			}
			inventoryArea.setLockedInv(inventoryArea.getLockedInv() + bookedArea);
			inventoryArea.setGmtModify(new Date());
			if (inventoryArea.getLockedInv() > inventoryArea.getInventory()) {
				throw new InventoryException(String.format(
						"insertLockedRecord inventory check exception : detailId[%d],StockStatus[%d],CalcInventory[%d],ActualInventory[%d]",
						erpOrder.getId(), warehouseCollector.getStockStatus(), booked, availableInv));
			}
			inventoryAreaMapper.updateSelectiveById(inventoryArea);
			inventoryRecordService
					.insert(buildLockedRecord(erpOrder, bookedArea, inventoryArea, skuId, InventoryType.INVENTORY));
			// 预定量为0直接推出循环
			if (booked == 0) {
				break;
			}
		}
		//计算实际锁定的数量
		if(booked>0){
			warehouseCollector.setBooked(warehouseCollector.getBooked()-booked);
		}
	}

	private void insertTransInventoryLockedRecord(ErpOrder erpOrder, WarehouseCollector warehouseCollector,
			int availableInv) throws InventoryException {
		Long itemId = erpOrder.getItemId();
		Long skuId = erpOrder.getSkuId();
		Long warehouseId = warehouseCollector.getWarehouseId();
		int booked = warehouseCollector.getTransBooked();
		List<InventoryArea> areas = inventoryAreaMapper.queryInventoryAreaByWarehouse(warehouseId, itemId, skuId);
		for (InventoryArea inventoryArea : areas) {
			int available = inventoryArea.getAvailableTransInv();
			if (available == 0) {
				continue;
			}
			int bookedArea = 0;
			if (booked >= available) {
				bookedArea = available;
				booked -= available;
			} else {
				bookedArea = booked;
				booked = 0;
			}
			inventoryArea.setLockedTransInv(inventoryArea.getLockedTransInv() + bookedArea);
			inventoryArea.setGmtModify(new Date());
			if (inventoryArea.getLockedTransInv() > inventoryArea.getTransInv()) {
				throw new InventoryException(String.format(
						"insertTransInventoryLockedRecord inventory check exception : detailId[%d],StockStatus[%d],CalcInventory[%d],ActualInventory[%d]",
						erpOrder.getId(), warehouseCollector.getStockStatus(), booked, availableInv));
			}
			inventoryAreaMapper.updateSelectiveById(inventoryArea);
			inventoryRecordService
					.insert(buildLockedRecord(erpOrder, bookedArea, inventoryArea, skuId, InventoryType.TRANS_INV));
			// 预定量为0直接推出循环
			if (booked == 0) {
				break;
			}
		}
		//计算实际锁定的数量
		if(booked>0){
			warehouseCollector.setTransBooked(warehouseCollector.getTransBooked()-booked);
		}
	}

	private InventoryRecord buildLockedRecord(ErpOrder erpOrder, int booked, InventoryArea inventory, Long skuId,
			InventoryType inventoryType) {
		InventoryRecord bookedRecord = new InventoryRecord();
		bookedRecord.setOrderId(erpOrder.getOuterOrderId());
		bookedRecord.setErpOrderId(erpOrder.getId());
		bookedRecord.setSkuId(skuId);
		bookedRecord.setItemId(erpOrder.getItemId());
		bookedRecord.setSkuCode(erpOrder.getSkuCode());
		bookedRecord.setInventory(inventory.getInventory());
		bookedRecord.setPositionNo(inventory.getPositionNo());
		bookedRecord.setBooked(booked);
		bookedRecord.setInventoryAreaId(inventory.getId());
		bookedRecord.setWarehouseId(inventory.getWarehouseId());
		bookedRecord.setQuantity(erpOrder.getQuantity());
		bookedRecord.setInventoryType(inventoryType);
		bookedRecord.setOperatorType(OperatorType.LOCKED);
		Date now = new Date();
		bookedRecord.setGmtCreate(now);
		bookedRecord.setGmtModify(now);
		return bookedRecord;
	}

	@Override
	public int updateLockInventory(Long id, int booked, int transBooked) {
		return inventoryMapper.updateLockInventory(id, booked, transBooked);
	}

	@Override
	public void deleteInventoryBySkuId(Long skuId) {
		inventoryMapper.deleteInventoryBySkuId(skuId);
	}

	@Override
	public List<WarehouseCollector> selectWarehousesByErpOrders(List<ErpOrder> erpOrders) throws InventoryException {
		if(CollectionUtils.isEmpty(erpOrders)){
			return null;
		}
		//Long:仓库ID,Long:erporderid,WarehouseCollector
		Table<Long, Long, WarehouseCollector> table = HashBasedTable.create();
		Map<Long,Integer> warehouseSeqMap = warehouseService.getWarehouseSeqMap();
		
		for (ErpOrder erpOrder : erpOrders) {
			if (erpOrder.getWarehouseId() != null) {
				throw new InventoryException(
						String.format("包含已经备货的仓库：erporderid=[%d],erpno=[%s]", erpOrder.getId(), erpOrder.getErpNo()));
			}
			List<InventoryArea> sumInventorys = inventoryAreaMapper.sumInventoryBySkuIdGroupbyWarehouse(erpOrder.getItemId(),
					erpOrder.getSkuId(),null);
			if (CollectionUtils.isNotEmpty(sumInventorys)) {
				for (InventoryArea inventory : sumInventorys) {
					if (inventory.getTotalAvailableInv() > 0) {
						WarehouseCollector whc = new WarehouseCollector();
						whc.setErpOrderId(erpOrder.getId());
						whc.setOrderId(erpOrder.getId());
						whc.setWarehouseId(inventory.getWarehouseId());
						whc.setQuantity(erpOrder.getQuantity());
						whc.setErpOrder(erpOrder);
						initBooked(inventory, whc);
						table.put(inventory.getWarehouseId(), whc.getErpOrderId(), whc);
					}
				}
			}
		}
		// 计算每个仓库下面的得分。
		if (!table.isEmpty()) {
			Map<Long, Double> scoreMap = Maps.newHashMap();
			Set<Long> rows = table.rowKeySet();
			for (Long wareId : rows) {
				Map<Long, WarehouseCollector> rowData = table.row(wareId);
				for (Entry<Long, WarehouseCollector> entry : rowData.entrySet()) {
					WarehouseCollector whc = entry.getValue();
					if (scoreMap.containsKey(wareId)) {
						Double d = scoreMap.get(wareId) + score(whc);
						scoreMap.put(wareId, d);
					} else {
						scoreMap.put(wareId, score(whc));
					}
				}
			}
			Long maxWareId = null;
			Double maxD = null;
			for (Long wareId : scoreMap.keySet()) {
				if (maxD == null) {
					maxWareId = wareId;
					maxD = scoreMap.get(wareId);
				} else {
					if (maxD < scoreMap.get(wareId)) {
						maxD = scoreMap.get(wareId);
						maxWareId = wareId;
					} else if(maxD.equals(scoreMap.get(wareId)) && warehouseSeqMap.get(wareId) > warehouseSeqMap.get(maxWareId)) {
						maxD = scoreMap.get(wareId);
						maxWareId = wareId;
					}
				}
			}
			if (maxWareId != null) {
				List<WarehouseCollector> wcs = Lists.newArrayList();
				Map<Long, WarehouseCollector> rowData = table.row(maxWareId);
				for (Entry<Long, WarehouseCollector> entry : rowData.entrySet()) {
					wcs.add(entry.getValue());
				}
				return wcs;
			}else{
				return null;
			}
		}
		return null;
	}

	/**
	 * 计算在指定仓库可以备货的库存数量
	 * @param inventory
	 * @param whc
	 */
	private void initBooked(InventoryArea inventory, WarehouseCollector whc) {
		
		int needBook = whc.getQuantity()-whc.getLastBooked()-whc.getLastTransBooked();
		if (inventory.getAvailableInv() > 0) {
			if ((needBook - inventory.getAvailableInv()) > 0) {
				needBook = needBook - inventory.getAvailableInv();
				whc.setBooked(inventory.getAvailableInv());
			} else {
				whc.setBooked(needBook);
				needBook=0;
			}
		}
		if (needBook > 0) {
			if (inventory.getAvailableTransInv() > 0) {
				if ((needBook - inventory.getAvailableTransInv()) > 0) {
					whc.setTransBooked(inventory.getAvailableTransInv());
				} else {
					whc.setTransBooked(needBook);
				}

			}

		}
	}

	private Double score(WarehouseCollector whc) {
		int qua = whc.getQuantity();
		//int allBooked = whc.getTransBooked()+whc.getBooked();		//在途不参与计分
		int allBooked = whc.getBooked();
		if(allBooked==0){
			return 0d;
		}
		if(qua==allBooked){//全部备货完成返回10分
			return 10d;
		}else{//部分备货按照比例返回 (备货数量/总数) * 10
			return allBooked/(qua*0.1d);
		}
	}

	@Override
	public void lockedInventroy(WarehouseCollector warehouseCollector) throws InventoryException {
		int bookedSum = warehouseCollector.getBooked() + warehouseCollector.getTransBooked();
		if (bookedSum == 0) {
			return ;
		}
		ErpOrder erpOrder =  warehouseCollector.getErpOrder();
		Long itemId = erpOrder.getItemId();
		Long skuId =erpOrder.getSkuId();
		// 悲观锁 锁定库存记录，防止并发
		Inventory inventory = inventoryMapper.getInventoryBySkuId(itemId, skuId);
		int availableInv = inventory.getAvailableInv();// 可售库存
		int availableTransInv = inventory.getAvailableTransInv();// 可用在途库存
		//校验库存是否足够
		if(availableInv<warehouseCollector.getBooked()||availableTransInv<warehouseCollector.getTransBooked()){
			throw new InventoryException(String.format(
					"data expiration exception : detailId[%d],StockStatus[%d],CalcInventory[%d],ActualInventory[%d],CalcTransInventory[%d],ActualTransInventory[%d]",
					warehouseCollector.getErpOrder().getId(), warehouseCollector.getStockStatus(), warehouseCollector.getBooked(), availableInv,
					inventory.getAvailableTransInv(), availableTransInv));
		}
		if(warehouseCollector.getBooked()>0){
			// 记录实际锁定记录
			insertInventoryLockedRecord(erpOrder, warehouseCollector, availableInv);
		}
		if(warehouseCollector.getTransBooked()>0){
			// 记录在途库存锁定记录
			insertTransInventoryLockedRecord(erpOrder, warehouseCollector, availableTransInv);
		}
		int records = inventoryMapper.updateLockInventory(inventory.getId(), warehouseCollector.getBooked(), warehouseCollector.getTransBooked());
		if (records == 0) {
			throw new InventoryException(String.format(
					"data expiration exception : detailId[%d],StockStatus[%d],CalcInventory[%d],ActualInventory[%d],CalcTransInventory[%d],ActualTransInventory[%d]",
					warehouseCollector.getErpOrder().getId(), warehouseCollector.getStockStatus(), warehouseCollector.getBooked(), availableInv,
					inventory.getAvailableTransInv(), availableTransInv));
		}
		
		ErpOrderUtil.calculateStockStatus(erpOrder, warehouseCollector.getBooked()+warehouseCollector.getLastBooked(), warehouseCollector.getLastTransBooked()+warehouseCollector.getTransBooked());
		erpOrder.setGmtModify(new Date());
		erpOrder.setWarehouseId(warehouseCollector.getWarehouseId());
		erpOrderService.updateById(erpOrder);//更新状态
	}

	@Override
	public WarehouseCollector selectWarehousesByErpOrder(ErpOrder erpOrder) throws InventoryException {
		if(erpOrder.getWarehouseId()==null){
			throw new InventoryException(
					String.format("子订单没有备货的仓库：erporderid=[%d],erpno=[%s]", erpOrder.getId(), erpOrder.getErpNo()));
		}
		WarehouseCollector warehouseColl = new WarehouseCollector();
		warehouseColl.setErpOrderId(erpOrder.getId());
		warehouseColl.setOrderId(erpOrder.getOuterOrderId());
		warehouseColl.setErpOrder(erpOrder);
		warehouseColl.setQuantity(erpOrder.getQuantity());
		warehouseColl.setWarehouseId(erpOrder.getWarehouseId());
		
		// 从预定记录里面查询已经预定的量
		List<InventoryRecord> inventoryRecords = inventoryRecordService
				.sumBookedByInventoryType(erpOrder.getOuterOrderId(), erpOrder.getId());
		if(CollectionUtils.isEmpty(inventoryRecords)){
			throw new InventoryException(
					String.format("子订单没有备货的记录：erporderid=[%d],erpno=[%s]", erpOrder.getId(), erpOrder.getErpNo()));
		}
		int lastBooked = 0;
		int lastTransBooked = 0;
		for(InventoryRecord inventoryRecord:inventoryRecords){
			if(inventoryRecord.getInventoryType()==InventoryType.TRANS_INV){
				lastTransBooked = inventoryRecord.getBooked();
			} else if(inventoryRecord.getInventoryType()==InventoryType.INVENTORY){
				lastBooked = inventoryRecord.getBooked();
			}
		}
		warehouseColl.setLastBooked(lastBooked);
		warehouseColl.setLastTransBooked(lastTransBooked);
		
		List<InventoryArea> sumInventorys = inventoryAreaMapper.sumInventoryBySkuIdGroupbyWarehouse(erpOrder.getItemId(),
				erpOrder.getSkuId(),warehouseColl.getWarehouseId());
		
		if(CollectionUtils.isNotEmpty(sumInventorys)){
			InventoryArea inventoryArea  = sumInventorys.get(0);
			if(inventoryArea.getTotalAvailableInv()>0){
				initBooked(inventoryArea, warehouseColl);
			}
		}
		return warehouseColl;
	}

	@Override
	public void updateVirtualInvByItemId(Long itemId) {
		
		inventoryMapper.updateVirtualInvByItemId(itemId);
	}

	@Override
	public void transInvCheckOut(Long inventoryAreaId, int quantity, Long storagerDetailtId) throws InventoryException {
		String onlineNumber = null;
		if (storagerDetailtId != null && storagerDetailtId != 0) {
			PurchaseStorageDetail one = purchaseStorageDetailMapper.selectById(storagerDetailtId);
			if (one.getOnlineQuantity() < quantity) {
				throw new InventoryException("盘出在途数超过该网购单的在途数量，该网购单号实际在途为："+ one.getOnlineQuantity());
			}
			one.setOnlineQuantity(one.getOnlineQuantity() - quantity);
			purchaseStorageDetailMapper.updateSelectiveById(one);

			onlineNumber = one.getOnlineNumber();
		}

		InventoryArea inventoryArea = inventoryAreaMapper.selectById(inventoryAreaId);
		if (inventoryArea == null) {
			throw new InventoryException(String.format("Inventory[id:%d] is not exist!", inventoryAreaId));
		}
		if (inventoryArea.getTransInv() < quantity) {
			throw new InventoryException(String.format("InventoryArea[%d] inventory less than check quantity[%d]",
					inventoryArea.getTransInv(), quantity));
		}
		int availableInv = inventoryArea.getTransInv() - inventoryArea.getLockedTransInv();
		if (availableInv < quantity) {
			int lockedCheckInv = quantity - availableInv;// 需要释放数量
			List<InventoryRecord> records = inventoryRecordService.sumInventoryCheckRecord(inventoryAreaId,InventoryType.TRANS_INV, Arrays.asList(OrderStatus.INIT.getCode()));
			for (InventoryRecord inventoryRecord : records) {
				int sumBooked = inventoryRecord.getBooked();
				lockedCheckInv -= sumBooked;
				ErpOrder erpOrder = erpOrderService.selectById(inventoryRecord.getErpOrderId());
				releaseInventory(erpOrder);
				if (lockedCheckInv <= 0) {
					break;
				}
			}
			if (lockedCheckInv > 0) {
				throw new InventoryException("inventoryCheck is not enough!");
			}
			inventoryArea = inventoryAreaMapper.selectById(inventoryAreaId);
		}
		// 1、减掉总库存
		Inventory inventory = inventoryMapper.getInventoryBySkuId(inventoryArea.getItemId(), inventoryArea.getSkuId());
		int inventoryRecords = inventoryMapper.updateInventoryTransNotoInv(inventory.getId(), inventory.getTransInv(),quantity);
		if (inventoryRecords <= 0) {
			throw new InventoryException("Inventory data expire exception!");
		}
		
		// 2、盘点减掉货架库存
		int inventoryAreaRecords = inventoryAreaMapper.updateInventoryAreaTransCheck(inventoryArea.getId(),inventoryArea.getTransInv(), quantity);
		if (inventoryAreaRecords <= 0) {
			throw new InventoryException("inventoryArea data expire exception!");
		}

		// 记录盘点日志
		String userCreate = null;
		try {
			ShiroUser su = ShiroUtil.getShiroUser();
			userCreate = su.getLoginName();
		} catch (Exception e) {
			throw new ErpCommonException("没有登入");
		}
		InventoryInout inventoryInout = new InventoryInout();
		inventoryInout.setCompanyId(inventory.getCompanyId());
		inventoryInout.setItemId(inventory.getItemId());
		inventoryInout.setSkuCode(inventory.getSkuCode());
		inventoryInout.setSkuId(inventory.getSkuId());
		inventoryInout.setItemId(inventory.getItemId());
		inventoryInout.setQuantity(quantity);
		inventoryInout.setInventoryAreaId(inventoryArea.getId());
		inventoryInout.setWarehouseId(inventoryArea.getWarehouseId());
		inventoryInout.setPositionNo(inventoryArea.getPositionNo());
		inventoryInout.setOnlineNumber(onlineNumber);
		inventoryInout.setOperatorType(InoutOperatorType.TRV_CHECK_OUT.getCode());
		inventoryInout.setUserCreate(userCreate);
		inventoryInout.setGmtCreate(new Date());
		inventoryInout.setGmtModify(new Date());
		inventoryInoutService.insert(inventoryInout);
	}

}
